package cn.dansj.common.utils.spring;

import cn.dansj.common.utils.json.JSONUtils;
import cn.dansj.common.utils.transfer.Verification;
import org.springframework.core.type.AnnotationMetadata;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

public abstract class AnnotationUtils extends org.springframework.core.annotation.AnnotationUtils {
    public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Object... attribute) {
        A annotation = org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation(annotatedElement, annotationType);
        return annotation == null ? newInstance(annotationType, attribute) : annotation;
    }

    public static <A extends Annotation> A findMergedAnnotation(Method method, Class<A> annotationType, Object... attribute) {
        A annotation = org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation(method, annotationType);
        return annotation == null ? newInstance(annotationType, attribute) : annotation;
    }

    public static <A extends Annotation> A findMergedAnnotation(Class<?> clazz, Class<A> annotationType, Object... attribute) {
        A annotation = org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation(clazz, annotationType);
        return annotation == null ? newInstance(annotationType, attribute) : annotation;
    }

    public static <A extends Annotation> A findUpMergedAnnotation(Method method, Class<A> annotationType, Object... attribute) {
        return hasAnnotation(method, annotationType) ? findMergedAnnotation(method, annotationType) : findMergedAnnotation(method.getDeclaringClass(), annotationType, attribute);
    }

    public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
        return element != null && org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation(element, annotationType);
    }

    @SafeVarargs
    public static boolean hasAnyAnnotation(AnnotatedElement element, Class<? extends Annotation>... annotationTypes) {
        return Arrays.stream(annotationTypes).anyMatch(annotationType -> hasAnnotation(element, annotationType));
    }

    public static <T extends Annotation> T synthesizeAnnotation(AnnotationMetadata annotationMetadata, Class<T> annotationType) {
        final Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(annotationType.getName());
        if (Verification.checkNull(annotationAttributes)) return newInstance(annotationType);
        return org.springframework.core.annotation.AnnotationUtils.synthesizeAnnotation(annotationAttributes, annotationType, null);
    }

    public static <T extends Annotation> T synthesizeAnnotation(Map<String, Object> annotationAttributes, Class<T> annotationType) {
        return org.springframework.core.annotation.AnnotationUtils.synthesizeAnnotation(annotationAttributes, annotationType, null);
    }

    public static <T extends Annotation> T newInstance(Class<T> annotationType, Object... attribute) {
        return AnnotationUtils.synthesizeAnnotation(JSONUtils.toJSONObject(attribute), annotationType, null);
    }
}
